package com.test.auth_db_auto.filter;

import com.test.auth_db_auto.response.BaseResponse;
import com.test.auth_db_auto.response.HttpResponse;
import com.test.auth_db_auto.support.oauth2.BootClientDetails;
import com.test.auth_db_auto.utils.HttpUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Base64;

/**
 * 认证不带客户端信息参数处理 filter
 * @ Author: .Mr
 * @ ClassName BootBasicAuthenticationFilter
 * @ Description TODO
 * @ date 2021/12/23 14:13
 * @ Version 1.0
 */

public class BootBasicAuthenticationFilter extends OncePerRequestFilter {

    private ClientDetailsService clientDetailsService;
    private PasswordEncoder encoder;
    public BootBasicAuthenticationFilter(ClientDetailsService clientDetailsService,PasswordEncoder encoder){
        this.clientDetailsService=clientDetailsService;
        this.encoder=encoder;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filter) throws ServletException, IOException {

        if(!request.getRequestURI().equals("/oauth/token")){  // 当请求是获取token令牌信息的url时，则进行信息验证，否则放行
            filter.doFilter(request,response);
            return;
        }

        String[] hasClientDetails = this.isHasClientDetails(request);

        if(hasClientDetails==null){
            BaseResponse bs = HttpResponse.baseResponse(HttpStatus.UNAUTHORIZED.value(), "请求中未包含客户端信息");
            HttpUtils.writer(bs, response);
            return;
        }

        this.handle(request,response,hasClientDetails,filter);
    }

    private void handle(HttpServletRequest request,HttpServletResponse response,String [] clientDetails,FilterChain filter) throws IOException, ServletException {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if(authentication!=null && authentication.isAuthenticated()){
            filter.doFilter(request,response);
            return;
        }

        BootClientDetails details = (BootClientDetails)clientDetailsService.loadClientByClientId(clientDetails[0]);
        if(!encoder.matches(clientDetails[1],details.getClientSecret())){  //  判断客户端的秘钥是否正确
            BaseResponse bs = HttpResponse.baseResponse(HttpStatus.UNAUTHORIZED.value(), "client secret error");
            HttpUtils.writer(bs,response);
            return;
        }

        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(details.getClientId(), details.getClientSecret(), details.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(token);


        filter.doFilter(request,response);
    }

    /**
     * 判断请求头中是否包含client信息，不包含返回null
     * */
    private String[] isHasClientDetails(HttpServletRequest request){
        String [] params =null;

        String header =request.getHeader(HttpHeaders.AUTHORIZATION);

        if(header!=null){
            String basic=header.substring(0,5);
            if(basic.toLowerCase().contains("basic")){
                String tmp=header.substring(6);
                String clientDetails = new String(Base64.getDecoder().decode(tmp));

                String[] clientArray = clientDetails.split(":");
                if(clientArray.length!=2){
                    return params;
                }else{
                    params=clientArray;
                }
            }
        }

        String client_id = request.getParameter("client_id");         // 公司提供给第三方访问的key
        String client_secret = request.getParameter("client_secret");  // 公司提供给第三方的访问秘钥

        if(header==null && client_id!=null){
            params=new String[]{client_id,client_secret};
        }
        return params;
    }

    public ClientDetailsService getClientDetailsService(){
        return clientDetailsService;
    }

    public void setClientDetailsService(ClientDetailsService clientDetailsService){
        this.clientDetailsService=clientDetailsService;
    }
}
